﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;

namespace SBWLogReader
{
    public class LogFile
    {
        private string _filePath = string.Empty;
        private string _fileName = string.Empty;
        private List<LogEntry> _logEntries = new List<LogEntry>();

        public List<LogEntry> LogEntries
        {
            get { return _logEntries; } 
        }

        public LogFile(string filePath)
        {
            this._filePath = filePath;
            this._fileName = Path.GetFileName(filePath);

            ReadLogFile();
        }
        
        /// <summary>
        /// Reads the log file in and populates the _logEntries collection
        /// </summary>
        private void ReadLogFile()
        {
            StreamReader reader = new StreamReader(_filePath);

            while (reader.Peek() != -1)
            {
                string[] line = reader.ReadLine().Split(',');

                // Ensure that the line has four entries
                if (line.Length == 4)
                {
                    // Add a new log entry
                    _logEntries.Add(new LogEntry()
                    {
                        LogFile = _fileName,
                        Hour = int.Parse(line[0]),
                        Login = line[1],
                        PacketsIn = int.Parse(line[2]),
                        PacketsOut = int.Parse(line[3])
                    });
                }
            }
        }        

        public override string ToString()
        {
            return _fileName;
        }
    }


    public class LogEntry
    {
        private const int _bytesInKB = 1024;
        private const int _bytesInMB = 1048576;
        private const int _bytesInGB = 1073741824;

        /// <summary>
        /// The name of the log file associated with this log entry
        /// </summary>
        public string LogFile = string.Empty;

        /// <summary>
        /// The hour this log entry is associated with
        /// </summary>
        public int Hour = 0;

        /// <summary>
        /// The user login for this log entry
        /// </summary>
        public string Login = string.Empty; 

        /// <summary>
        /// The number of packets sent to the database
        /// </summary>
        public int PacketsIn = 0;

        /// <summary>
        /// The number of packets received from the database
        /// 
        /// </summary>
        public int PacketsOut = 0;

        /// <summary>
        /// The total number of packets sent and recevied from the database
        /// </summary>
        public int TotalPackets
        {
            get
            {
                return PacketsIn + PacketsOut;
            }
        }

        private decimal _bandwidthIn = -1;
        private decimal _bandwidthOut = -1;

        /// <summary>
        /// Calculates the bandwidth used for this log entry from the client to the database
        /// </summary>
        /// <param name="unit"></param>
        /// <param name="bytesPerPacket"></param>
        /// <returns></returns>
        public decimal BandwidthIn(BandwidthUnit unit, int bytesPerPacket, bool rounded)
        {
            if (_bandwidthIn == -1)
            {
                decimal bytesIn = (decimal)PacketsIn * bytesPerPacket;

                switch (unit)
                {
                    case BandwidthUnit.B:
                        _bandwidthIn = bytesIn;
                        break;
                    case BandwidthUnit.KB:
                        _bandwidthIn = bytesIn / _bytesInKB;
                        break;
                    case BandwidthUnit.MB:
                        _bandwidthIn = bytesIn / _bytesInMB;
                        break;
                    case BandwidthUnit.GB:
                        _bandwidthIn = bytesIn / _bytesInGB;
                        break;
                }
            }

            if (rounded)
                return decimal.Round(_bandwidthIn, 2);

            return _bandwidthIn;
        }

        /// <summary>
        /// Calculates the bandwidth used for this log entry from the database to the client
        /// </summary>
        /// <param name="unit"></param>
        /// <param name="bytesPerPacket"></param>
        /// <returns></returns>
        public decimal BandwidthOut(BandwidthUnit unit, int bytesPerPacket, bool rounded)
        {
            if (_bandwidthOut == -1)
            {
                decimal bytesIn = (decimal)PacketsOut * bytesPerPacket;

                switch (unit)
                {
                    case BandwidthUnit.B:
                        _bandwidthOut = bytesIn;
                        break;
                    case BandwidthUnit.KB:
                        _bandwidthOut = bytesIn / _bytesInKB;
                        break;
                    case BandwidthUnit.MB:
                        _bandwidthOut = bytesIn / _bytesInMB;
                        break;
                    case BandwidthUnit.GB:
                        _bandwidthOut = bytesIn / _bytesInGB;
                        break;
                }
            }

            if (rounded)
                return decimal.Round(_bandwidthOut, 2);

            return _bandwidthOut;
        }

        /// <summary>
        /// Calculates the total bandwidth used for this log entry
        /// </summary>
        /// <param name="unit"></param>
        /// <param name="bytesPerPacket"></param>
        /// <returns></returns>
        public decimal TotalBandwidth(BandwidthUnit unit, int bytesPerPacket, bool rounded)
        {
            decimal totalBandwidth = BandwidthIn(unit, bytesPerPacket, false) + BandwidthOut(unit, bytesPerPacket, false);

            // Reset the cached values as a change in the bytes per packet
            // or the bandwidth unit will require recalculation
            _bandwidthIn = -1;
            _bandwidthOut = -1;

            if (rounded)
                return decimal.Round(totalBandwidth, 2);

            return totalBandwidth;
        }
    }

    public enum BandwidthUnit
    {
        B, KB, MB, GB        
    }
}
